from functools import wraps
import babel
from contextlib import contextmanager
import datetime
import subprocess
import io
import os

import collections
import passlib.utils
import pickle as pickle_
import re
import socket
import sys
import threading
import time
import types
import unicodedata
import werkzeug.utils
import zipfile
from collections import defaultdict, Iterable, Mapping, MutableMapping, MutableSet, OrderedDict
from itertools import islice, groupby as itergroupby, repeat
from lxml import etree

from .which import which
import traceback
from operator import itemgetter

try:
    import cProfile
except ImportError:
    import profile as cProfile

from .config import config
from .cache import *
from .parse_version import parse_version
from . import pycompat

import odoo
from odoo.loglevels import get_encodings, ustr, exception_to_unicode

_logger = logging.getLogger(__name__)

SKIPPED_ELEMENT_TYPES = (etree._Comment, etree._ProcessingInstruction, etree.CommentBase, etree.PIBase, etree._Entity)

etree.set_default_parser(etree.XMLParser(resolve_entities=False))

def find_in_path(name):
    pass

def _exec_pipe(prog, args, env=None):
    pass

def exec_command_pipe(name, *args):
    pass

def find_pg_tool(name):
    pass

def exec_pg_environ():
    pass

def exec_pg_command(name, *args):
    pass

def exec_pg_command_pipe(name, *args):
    pass

def file_open(name, mode="r", subdir='addons', pathinfo=False):
    """Open a file from the OpenERP root, using a subdir folder.

       Example::

       >>> file_open('hr/report/timesheer.xsl')
       >>> file_open('addons/hr/report/timesheet.xsl')

       @param name name of the file
       @param mode file open mode
       @param subdir subdirectory
       @param pathinfo if True returns tuple (fileobject, filepath)

       @return fileobject if pathinfo is False else (fileobject, filepath)
       """
    import odoo.modules as addons
    adps = addons.module.ad_paths
    rtp = os.path.normcase(os.path.abspath(config['root_path']))

    basename = name

    if os.path.isabs(name):
        name = os.path.normcase(os.path.normpath(name))
        for root in adps + [rtp]:
            root = os.path.normcase(os.path.normpath(root)) + os.sep
            if name.startswith(root):
                base = root.rstrip(os.sep)
                name = name[len(base) + 1:]
                break
        else:
            base, name = os.path.split(name)
        return _fileopen(name, mode=mode, basedir=base, pathinfo=pathinfo, basename=basename)

    if name.replace(os.sep, '/').startswith('addons/'):
        subdir = 'addons'
        name2 = name[7:]
    elif subdir:
        name = os.path.join(subdir, name)
        if name.replace(os.sep, '/').startswith('addons/'):
            subdir = 'addons'
            name2 = name[7:]
        else:
            name2 = name

    if subdir:
        for adp in adps:
            try:
                return _fileopen(name2, mode=mode, basedir=adp,
                                 pathinfo=pathinfo, basename=basename)
            except IOError:
                pass

    return _fileopen(name, mode=mode, basedir=rtp, pathinfo=pathinfo, basename=basename)

def _fileopen(path, mode, basedir, pathinfo, basename=None):
    name = os.path.normpath(os.path.normcase(os.path.join(basedir, path)))

    import odoo.modules as addons
    paths = addons.module.ad_paths + [config['root_path']]
    for addons_path in paths:
        addons_path = os.path.normpath(os.path.normcase(addons_path)) + os.sep
        if name.startswith(addons_path):
            break
    else:
        raise ValueError("Unknown path: %s" % name)

    if basename is None:
        basename = name
    # Give higher priority to module directories, which is
    # a more common case than zipped modules.
    if os.path.isfile(name):
        if 'b' in mode:
            fo = open(name, mode)
        else:
            fo = io.open(name, mode, encoding='utf-8')
        if pathinfo:
            return fo, name
        return fo

def flatten(list):
    pass

def reverse_enumerate(l):
    return pycompat.izip(range(len(l) - 1, -1, -1), reversed(l))

def partition(pred, elems):
    pass

def topological_sort(elems):
    pass

try:
    import xlwt

    class PatchedWorkbook(xlwt.Workbook):
        def add_sheet(self, name, cell_overwrite_ok=False):
            pass

    xlwt.Workbook = PatchedWorkbook
except ImportError:
    xlwt = None

try:
    import xlsxwriter

    class PatchedXlsxWorkbook(xlsxwriter.Workbook):
        def add_worksheet(self, name=None, **kw):
            pass

    xlsxwriter.Workbook = PatchedXlsxWorkbook

except ImportError:
    xlsxwriter = None

def to_xml(s):
    pass

def get_iso_codes(lang):
    pass

def scan_languages():
    csvpath = odoo.modules.module.get_resource_path('base', 'data', 'res.lang.csv')
    try:
        with open(csvpath, 'rb') as csvfile:
            reader = pycompat.csv_reader(csvfile, delimiter=',', quotechar='"')
            fields = next(reader)
            code_index = fields.index("code")
            name_index = fields.index("name")
            result = [
                (row[code_index], row[name_index])
                for row in reader
            ]
    except Exception:
        _logger.error("Could not read %s", csvpath)
        result = []

    return sorted(result or [('en_US', u'English')], key=itemgetter(1))

def get_user_companies(cr, user):
    pass

def mod10r(number):
    pass

def str2bool(s, default=None):
    pass

def human_size(sz):
    pass

def logged(f):
    pass

class profile(object):
    def __init__(self, fname=None):
        pass

    def __call__(self, f):
        pass

def detect_ip_addr():
    pass

DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d"
DEFAULT_SERVER_TIME_FORMAT = "%H:%M:%S"
DEFAULT_SERVER_DATETIME_FORMAT = "%s %s" % (
    DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_TIME_FORMAT)

DATE_LENGTH = len(datetime.date.today().strftime(DEFAULT_SERVER_DATE_FORMAT))

DATETIME_FORMATS_MAP = {
        '%C': '', # century
        '%D': '%m/%d/%Y', # modified %y->%Y
        '%e': '%d',
        '%E': '', # special modifier
        '%F': '%Y-%m-%d',
        '%g': '%Y', # modified %y->%Y
        '%G': '%Y',
        '%h': '%b',
        '%k': '%H',
        '%l': '%I',
        '%n': '\n',
        '%O': '', # special modifier
        '%P': '%p',
        '%R': '%H:%M',
        '%r': '%I:%M:%S %p',
        '%s': '', #num of seconds since epoch
        '%T': '%H:%M:%S',
        '%t': ' ', # tab
        '%u': ' %w',
        '%V': '%W',
        '%y': '%Y', # Even if %y works, it's ambiguous, so we should use %Y
        '%+': '%Y-%m-%d %H:%M:%S',
        '%z': '',
        '%Z': '',
}

POSIX_TO_LDML = {
    'a': 'E',
    'A': 'EEEE',
    'b': 'MMM',
    'B': 'MMMM',
    #'c': '',
    'd': 'dd',
    'H': 'HH',
    'I': 'hh',
    'j': 'DDD',
    'm': 'MM',
    'M': 'mm',
    'p': 'a',
    'S': 'ss',
    'U': 'w',
    'w': 'e',
    'W': 'w',
    'y': 'yy',
    'Y': 'yyyy',
}

def posix_to_ldml(fmt, locale):
    pass

def split_every(n, iterable, piece_maker=tuple):
    pass

def get_and_group_by_field(cr, uid, obj, ids, field, context=None):
    pass

def get_and_group_by_company(cr, uid, obj, ids, context=None):
    pass

def resolve_attr(obj, attr):
    pass

def attrgetter(*items):
    pass

def remove_accents(input_str):
    pass

class unquote(str):
    def __repr__(self):
        pass

class UnquoteEvalContext(defaultdict):
    def __init__(self, *args, **kwargs):
        pass

    def __missing__(self, key):
        pass

class mute_logger(object):
    def __init__(self, *loggers):
        self.loggers = loggers

    def filter(self, record):
        return 0

    def __enter__(self):
        for logger in self.loggers:
            pass

    def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
        pass

    def __call__(self, func):
        @wraps(func)
        def deco(*args, **kwargs):
            with self:
                return func(*args, **kwargs)
        return deco

_ph = object()
class CountingStream(object):
    def __init__(self, stream, start=-1):
        pass

    def __iter__(self):
        pass

    def next(self):
        pass

    __next__ = next

def stripped_sys_argv(*strip_args):
    pass

class ConstantMapping(Mapping):
    __slots__ = ['_value']
    def __init__(self, val):
        pass

    def __len__(self):
        pass

    def __iter__(self):
        pass

    def __getitem__(self, item):
        pass

def dumpstacks(sig=None, frame=None, thread_idents=None):
    pass

def freehash(arg):
    pass

def clean_context(context):
    pass

class frozendict(dict):
    def __delitem__(self, key):
        pass
    def __setitem__(self, key, val):
        pass
    def clear(self):
        pass
    def pop(self, key, default=None):
        pass
    def popitem(self):
        pass
    def setdefault(self, key, default=None):
        pass
    def update(self, *args, **kwargs):
        pass
    def __hash__(self):
        pass

class Collector(Mapping):
    """ An implementation of an immutable dictionary. """
    __slots__ = ['_map']
    def __init__(self):
        pass
    def add(self, key, val):
        pass
    def __getitem__(self, key):
        pass
    def __iter__(self):
        pass
    def __len__(self):
        pass

@pycompat.implements_to_string
class StackMap(MutableMapping):

    __slots__ = ['_map']

    def __init__(self):
        pass

    def add(self, key, val):
        pass

    def __getitem__(self, key):
        pass

    def __iter__(self):
        pass

    def __len__(self):
        pass

@pycompat.implements_to_string
class StackMap(MutableMapping):
    __slots__ = ['_maps']

    def __init__(self, m=None):
        self._maps = [] if m is None else [m]

    def __getitem__(self, key):
        pass

    def __setitem__(self, key, val):
        pass

    def __delitem__(self, key):
        pass

    def __iter__(self):
        pass

    def __len__(self):
        pass

    def __str__(self):
        pass

    def pushmap(self, m=None):
        pass

    def popmap(self):
        pass

class OrderedSet(MutableSet):
    __slots__ = ['_map']
    def __init__(self, elems=()):
        pass
    def __contains__(self, elem):
        pass
    def __iter__(self):
        pass
    def __len__(self):
        pass
    def add(self, elem):
        pass
    def discard(self, elem):
        pass

class LastOrderedSet(OrderedSet):
    def add(self, elem):
        pass

def groupby(iterable, key=None):
    pass

def unique(it):
    pass

class Reverse(object):
    __slots__ = ['val']

    def __init__(self, val):
        pass

    def __eq__(self, other): return self.val == other.val
    def __ne__(self, other): return self.val != other.val

    def __ge__(self, other): return self.val <= other.val
    def __gt__(self, other): return self.val < other.val
    def __le__(self, other): return self.val >= other.val
    def __lt__(self, other): return self.val > other.val

@contextmanager
def ignore(*exc):
    try:
        yield
    except exc:
        pass

if parse_version(getattr(werkzeug, '__version__', '0.0')) < parse_version('0.9.0'):
    def html_escape(text):
        return werkzeug.utils.escape(text, quote=True)
else:
    def html_escape(text):
        pass

def babel_locale_parse(lang_code):
        pass
def formatLang(env, value, digits=None, grouping=True, monetary=False, dp=False, currency_obj=False):
    pass

def format_date(env, value, lang_code=False, date_format=False):
    pass

def _consteq(str1, str2):
    pass

consteq = getattr(passlib.utils, 'consteq', _consteq)

class Unpickler(pickle_.Unpickler, object):
    find_global = None  # Python 2
    find_class = None  # Python 3

def _pickle_load(stream, encoding='ASCII', errors=False):
    pass

pickle = types.ModuleType(__name__ + '.pickle')
pickle.load = _pickle_load
pickle.loads = lambda text, encoding='ASCII': _pickle_load(io.BytesIO(text), encoding=encoding)
pickle.dump = pickle_.dump
pickle.dumps = pickle_.dumps

def wrap_values(d):
    pass

import shutil
_missing = object()
_cache = dict.fromkeys([os, os.path, shutil, sys, subprocess])
def wrap_module(module, attr_list):
    wrapper = _cache.get(module)
    if wrapper:
        pass

    attr_list = attr_list and set(attr_list)
    class WrappedModule(object):
        def __getattr__(self, attrib):
            pass

    wrapper = WrappedModule()
    _cache.setdefault(module, wrapper)
    return wrapper

import dateutil
mods = ['parser', 'relativedelta', 'rrule', 'tz']
for mod in mods:
    __import__('dateutil.%s' % mod)
attribs = [attr for m in mods for attr in getattr(dateutil, m).__all__]
dateutil = wrap_module(dateutil, set(mods + attribs))
datetime = wrap_module(datetime, ['date', 'datetime', 'time', 'timedelta', 'timezone', 'tzinfo', 'MAXYEAR', 'MINYEAR'])

class DotDict(dict):
    def __getattr__(self, attrib):
        pass

def traverse_containers(val, type_):
    pass
